import sys
from pathlib import Path
import time
import streamlit as st
import requests

# -------------------------- 项目根目录配置 --------------------------
app_py_path = Path(__file__).resolve()
project_root = app_py_path.parent.parent.parent

if str(project_root) not in sys.path:
    sys.path.insert(0, str(project_root))

# 配置导入
try:
    from config.app_config import get_app_config

    config = get_app_config()
    API_BASE_URL = f"http://{config.api_host}:{config.api_port}"
    MANAGEMENT_API_URL = f"{API_BASE_URL}/management/documents"
    QA_API_URL = f"{API_BASE_URL}/qa/query"
    SUPPORTED_EXTENSIONS = config.supported_document_extensions
except ImportError as e:
    st.error("无法加载配置文件，请检查项目结构")
    st.stop()


def main():
    st.set_page_config(page_title="知识库管理后台", layout="wide")
    st.title("📚 知识库管理系统")

    # 初始化session_state
    if "docs" not in st.session_state:
        st.session_state.docs = []
    if "selected_doc_id" not in st.session_state:
        st.session_state.selected_doc_id = None
    if "show_chunks" not in st.session_state:
        st.session_state.show_chunks = False
    if "last_refresh_time" not in st.session_state:
        st.session_state.last_refresh_time = 0
    if "delete_confirmation" not in st.session_state:
        st.session_state.delete_confirmation = False
    if "pending_delete_id" not in st.session_state:
        st.session_state.pending_delete_id = ""

    # 刷新文档列表
    def refresh_documents(force=False):
        current_time = time.time()
        if not force and (current_time - st.session_state.last_refresh_time) < 5:
            return False
        try:
            response = requests.get(f"{MANAGEMENT_API_URL}/list", timeout=10)
            response.raise_for_status()
            st.session_state.docs = response.json()
            st.session_state.last_refresh_time = current_time
            return True
        except Exception as e:
            st.error(f"加载文档列表失败: {str(e)}", icon="❌")
            return False

    # 查看文档片段回调
    def handle_view(doc_id):
        st.session_state.selected_doc_id = doc_id
        st.session_state.show_chunks = True
        st.session_state.delete_confirmation = False  # 关闭删除确认

    # 删除文档回调
    def handle_delete(doc_id):
        st.session_state.pending_delete_id = doc_id
        st.session_state.delete_confirmation = True
        st.session_state.show_chunks = False  # 关闭片段查看

    # 页面导航
    page = st.sidebar.radio(
        "功能选择",
        ["文档上传", "文档列表", "知识库问答", "系统配置"],
        index=0,
        key="page_selector"
    )

    # 切换页签刷新数据
    if page != st.session_state.get("current_page"):
        st.session_state.current_page = page
        if page == "文档列表":
            with st.spinner("加载文档数据..."):
                refresh_documents(force=True)
        else:
            st.session_state.show_chunks = False
            st.session_state.selected_doc_id = None

    # -------------------------- 文档上传页面 --------------------------
    if page == "文档上传":
        st.header("📤 文档上传")
        st.info(f"支持格式：{', '.join(SUPPORTED_EXTENSIONS)}（自动去重）")

        uploaded_files = st.file_uploader(
            "选择文件（可多选）",
            type=[ext.strip('.') for ext in SUPPORTED_EXTENSIONS],
            accept_multiple_files=True
        )

        if uploaded_files and st.button("开始处理", type="primary", use_container_width=True):
            with st.spinner("处理中（解析→切片→存储）..."):
                try:
                    files = [("files", (f.name, f, f.type)) for f in uploaded_files]
                    response = requests.post(
                        f"{MANAGEMENT_API_URL}/upload",
                        files=files,
                        timeout=300
                    )
                    response.raise_for_status()
                    result = response.json()

                    st.success("✅ 处理完成！", icon="✅")
                    if result["success"]:
                        with st.expander(f"成功文件（{len(result['success'])}个）", expanded=True):
                            for item in result["success"]:
                                st.write(f"- {item}")
                    if result["failed"]:
                        with st.expander(f"失败文件（{len(result['failed'])}个）", expanded=True):
                            for item in result["failed"]:
                                st.error(f"- {item}", icon="❌")

                    if st.button("查看文档列表", use_container_width=True):
                        st.session_state.page_selector = "文档列表"
                        st.experimental_rerun()

                except requests.exceptions.Timeout:
                    st.error("❌ 处理超时，请尝试拆分文件", icon="⏰")
                except Exception as e:
                    st.error(f"❌ 处理失败：{str(e)}", icon="❌")
        elif not uploaded_files:
            st.info("请选择要上传的文件", icon="ℹ️")

    # -------------------------- 文档列表页面（彻底修复React错误） --------------------------
    elif page == "文档列表":
        st.header("📋 文档列表")

        col1, col2 = st.columns([1, 8])
        with col1:
            if st.button("🔄 刷新", use_container_width=True):
                with st.spinner("刷新中..."):
                    refresh_documents(force=True)
        with col2:
            st.caption(f"上次刷新: {time.strftime('%H:%M:%S', time.localtime(st.session_state.last_refresh_time))}")

        if st.session_state.docs:
            # 用Streamlit原生组件构建表格（避免HTML和JS）
            for i, doc in enumerate(st.session_state.docs):
                # 为每行创建唯一的key（避免组件冲突）
                row_key = f"row_{i}_{doc['doc_id']}"

                # 构建一行数据
                cols = st.columns([3, 3, 1, 1, 2])  # 调整列宽比例

                with cols[0]:
                    st.write(doc["file_name"])
                with cols[1]:
                    st.write(doc["upload_time"])
                with cols[2]:
                    st.write(doc["chunk_count"])
                with cols[3]:
                    st.write(doc["status"])
                with cols[4]:
                    # 🔴 核心修复：用Streamlit原生按钮替代HTML按钮
                    col_btn1, col_btn2 = st.columns(2)
                    with col_btn1:
                        st.button(
                            "查看",
                            key=f"view_{row_key}",
                            on_click=handle_view,
                            args=(doc["doc_id"],),
                            use_container_width=True
                        )
                    with col_btn2:
                        st.button(
                            "删除",
                            key=f"delete_{row_key}",
                            on_click=handle_delete,
                            args=(doc["doc_id"],),
                            use_container_width=True,
                            type="secondary"
                        )

                # 行分隔线
                if i != len(st.session_state.docs) - 1:
                    st.markdown("---")

            # 删除确认对话框
            if st.session_state.delete_confirmation and st.session_state.pending_delete_id:
                doc_name = next(
                    (doc["file_name"] for doc in st.session_state.docs if
                     doc["doc_id"] == st.session_state.pending_delete_id),
                    st.session_state.pending_delete_id
                )

                st.warning(f"确定要删除文档「{doc_name}」吗？此操作不可恢复！", icon="⚠️")
                col_confirm, col_cancel = st.columns(2)
                with col_confirm:
                    if st.button("确认删除", type="primary", use_container_width=True):
                        with st.spinner("删除中..."):
                            try:
                                response = requests.delete(
                                    f"{MANAGEMENT_API_URL}/delete/{st.session_state.pending_delete_id}",
                                    timeout=10
                                )
                                response.raise_for_status()
                                st.success("删除成功！", icon="✅")
                                st.session_state.delete_confirmation = False
                                st.session_state.pending_delete_id = ""
                                refresh_documents(force=True)
                            except Exception as e:
                                st.error(f"删除失败：{str(e)}", icon="❌")
                # 修改“删除确认对话框”中的取消按钮代码
                with col_cancel:
                    if st.button("取消", use_container_width=True, key="cancel_delete_btn"):  # 增加唯一key
                        st.session_state.delete_confirmation = False
                        st.session_state.pending_delete_id = ""
                        st.rerun()  # 强制刷新页面，立即反映状态变化

            # 显示文档片段
            # 替换“显示文档片段”部分的关闭按钮代码
            if st.session_state.show_chunks and st.session_state.selected_doc_id:
                doc_name = next(
                    (doc["file_name"] for doc in st.session_state.docs if
                     doc["doc_id"] == st.session_state.selected_doc_id),
                    st.session_state.selected_doc_id
                )

                with st.container(border=True):
                    st.subheader(f"🔍 文档片段：{doc_name}")

                    # 优化关闭按钮：添加唯一key，避免状态冲突
                    if st.button("关闭片段查看", use_container_width=True, key="close_chunks_btn"):
                        # 仅修改状态，不做其他操作
                        st.session_state.show_chunks = False
                        st.session_state.selected_doc_id = None
                        # 可选：强制刷新当前页面，避免状态残留
                        st.experimental_rerun()  # 新增：立即刷新页面，隐藏片段

                    with st.spinner("加载片段..."):
                        try:
                            chunk_response = requests.get(
                                f"{MANAGEMENT_API_URL}/{st.session_state.selected_doc_id}/chunks",
                                timeout=10
                            )
                            chunk_response.raise_for_status()
                            chunks = chunk_response.json()

                            if chunks:
                                chunks.sort(key=lambda x: x.get("chunk_index", 0))
                                chunk_count = len(chunks)
                                page_size = 3
                                total_pages = (chunk_count + page_size - 1) // page_size
                                current_page = st.number_input("页码", 1, total_pages, 1)

                                start_idx = (current_page - 1) * page_size
                                end_idx = min(start_idx + page_size, chunk_count)
                                st.caption(f"共 {chunk_count} 个片段（显示 {start_idx + 1}-{end_idx}）")

                                for chunk in chunks[start_idx:end_idx]:
                                    with st.expander(
                                            f"片段 {chunk.get('chunk_index')}（{len(chunk.get('page_content', ''))}字）",
                                            expanded=True):
                                        st.write(chunk.get('page_content', '无内容'))
                            else:
                                st.info("该文档暂无片段数据", icon="ℹ️")

                        except Exception as e:
                            st.error(f"加载片段失败：{str(e)}", icon="❌")

        else:
            st.info("暂无文档数据，请先上传文档", icon="ℹ️")
            if st.button("前往上传文档", use_container_width=True):
                st.session_state.page_selector = "文档上传"
                st.rerun()  # 替换为正式API

    # -------------------------- 知识库问答页面 --------------------------
    elif page == "知识库问答":
        st.header("❓ 知识库问答")
        st.info("基于已上传文档内容进行问答")

        try:
            config_response = requests.get(f"{API_BASE_URL}/qa/config", timeout=5)
            default_top_k = config_response.json().get("default_top_k", 3)
        except:
            default_top_k = 3

        question = st.text_area("请输入问题", placeholder="例如：XX的核心功能是什么？", height=100)
        with st.expander("高级参数"):
            top_k = st.slider("检索文档数量", 1, 10, default_top_k)

        if st.button("获取答案", type="primary", use_container_width=True):
            if not question.strip():
                st.warning("请输入问题内容", icon="⚠️")
                return

            with st.spinner("检索并生成答案..."):
                try:
                    response = requests.post(
                        QA_API_URL,
                        json={"question": question, "top_k": top_k},
                        timeout=60
                    )
                    response.raise_for_status()
                    result = response.json()

                    with st.container(border=True):
                        st.subheader("💡 回答结果")
                        st.write(result["answer"])

                    if result["related_docs"]:
                        with st.expander(f"参考片段（{len(result['related_docs'])}条）", expanded=False):
                            for i, doc in enumerate(result["related_docs"], 1):
                                st.write(f"片段{i}：{doc[:200]}...")

                except Exception as e:
                    st.error(f"问答失败：{str(e)}", icon="❌")

    # -------------------------- 系统配置页面 --------------------------
    elif page == "系统配置":
        st.header("⚙️ 系统配置")
        with st.container(border=True):
            st.subheader("路径配置")
            st.write(f"- 项目根目录：`{config.project_root}`")
            st.write(f"- 文档存储：`{config.raw_docs_path}`")
            st.write(f"- 向量库：`{config.vector_db_path}`")
            st.write(f"- 元数据库：`{config.metadata_db_path}`")

        with st.container(border=True):
            st.subheader("处理参数")
            st.write(f"- 切片长度：`{config.chunk_size}`字符")
            st.write(f"- 重叠长度：`{config.chunk_overlap}`字符")
            st.write(f"- 向量集合名：`{config.collection_name}`")

        with st.container(border=True):
            st.subheader("服务配置")
            st.write(f"- API地址：`{API_BASE_URL}`")
            st.write(f"- 支持格式：`{', '.join(SUPPORTED_EXTENSIONS)}`")


if __name__ == "__main__":
    main()
